#include "worklistdialog.h"
#include "ui_worklistdialog.h"
#include "wlistpatient.h"
#include "dcmtk/dcmdata/dcuid.h"
#include "../share/global.h"
#include "../MainStation/mainwindow.h"
#include "patientselectdialog.h"
#include "sqlpatientmodel.h"

#include <QDir>
#include <QSettings>
#include <QMessageBox>
#include <QSqlDatabase>
#include <QSqlQueryModel>
#include <QCompleter>

WorkListDialog::WorkListDialog(WListPatient *const &_patient, EditMode _mode, QWidget *parent) :
    patient(_patient),
    mode(_mode),
    QDialog(parent),
    ui(new Ui::WorkListDialog)
{
    ui->setupUi(this);
    if (mode == NewPatient) setWindowTitle(tr("Register New Patient"));
    else if (mode == NewStudy) setWindowTitle(tr("Register New Study"));
    else if (mode == ChangeStudy) setWindowTitle(tr("Change Study"));

    init();

    connect(ui->okButton, SIGNAL(clicked()), this, SLOT(onOk()));
    connect(ui->clearButton, SIGNAL(clicked()), this, SLOT(onClear()));
    connect(ui->patientAgeSpin, SIGNAL(valueChanged(int)), this, SLOT(updateBirth()));
    connect(ui->ageUnitCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateBirth()));
    connect(ui->patientBirthDateEdit, SIGNAL(dateChanged(QDate)), this, SLOT(updateAge(QDate)));
    connect(completer, SIGNAL(activated(QString)), this, SLOT(patientSelected(QString)));
}

WorkListDialog::~WorkListDialog()
{
    delete ui;
}

void WorkListDialog::init()
{
    QSettings settings;

    QStringList strlist;
    strlist = settings.value(MEDICAL_ALERTS).toStringList();
    strlist.prepend("");
    ui->medicalAlertsCombo->addItems(strlist);
    strlist = settings.value(PATIENT_ADDR).toStringList();
    strlist.prepend("");
    ui->patientAddrCombo->addItems(strlist);
    strlist = settings.value(PATIENT_PHONES).toStringList();
    strlist.prepend("");
    ui->patientPhoneCombo->addItems(strlist);
    strlist = settings.value(ADMISSION_IDS).toStringList();
    strlist.prepend("");
    ui->admissionIdCombo->addItems(strlist);
    strlist = settings.value(REQ_PHYSICIANS).toStringList();
    ui->reqPhysicianCombo->addItems(strlist);
    strlist = settings.value(REQ_DIVISIONS).toStringList();
    ui->divisionCombo->addItems(strlist);
    strlist = settings.value(PROCEDURE_IDS).toStringList();
    ui->reqProcIDCombo->addItems(strlist);
    strlist = settings.value(PROCEDURE_DESC).toStringList();
    ui->reqProcDescCombo->addItems(strlist);
    strlist = settings.value(PER_PHYSICIANS).toStringList();
    ui->schPhysicianCombo->addItems(strlist);
    strlist = settings.value(STATION_AETS).toStringList();
    ui->schStationAETCombo->addItems(strlist);
    strlist = settings.value(STATION_NAMES).toStringList();
    ui->schStationNameCombo->addItems(strlist);
    strlist = settings.value(PROC_STEP_ID).toStringList();
    ui->schProcStepIDCombo->addItems(strlist);
    strlist = settings.value(PROC_STEP_DESC).toStringList();
    ui->schProcStepDescCombo->addItems(strlist);
    ui->patientBirthDateEdit->setMaximumDate(QDate::currentDate().addDays(-1));

    ui->accNumberEdit->setText(patient->accNumber);
    ui->patientIDEdit->setText(patient->patientID);
    ui->patientNameEdit->setText(patient->patientName);
    if (patient->patientSex == "M") {
        ui->patientSexCombo->setCurrentIndex(0);
    } else if (patient->patientSex == "F") {
        ui->patientSexCombo->setCurrentIndex(1);
    } else if (patient->patientSex == "O") {
        ui->patientSexCombo->setCurrentIndex(2);
    }
    if (patient->patientBirth.isValid()) {
        ui->patientBirthDateEdit->setDate(patient->patientBirth);
    }
    updateAge(ui->patientBirthDateEdit->date(), true);
    ui->patientSizeDSpin->setValue(patient->patientSize);
    ui->patientWeightDSpin->setValue(patient->patientWeight);
    ui->patientPhoneCombo->setCurrentText(patient->patientPhone);
    ui->patientAddrCombo->setCurrentText(patient->patientAddress);
    ui->medicalAlertsCombo->setCurrentText(patient->medicalAlerts);
    ui->admissionIdCombo->setCurrentText(patient->admissionID);
    ui->divisionCombo->setCurrentText(patient->department);
    switch (mode) {
    case NewPatient: {
        const CustomizedId &pidf = mainWindow->getPatientIdFormat();
        int start = settings.value(PATIENTID_START).toInt();
        ui->patientIDEdit->setText(QString("%1%2%3").arg(pidf.prefix)
                                   .arg(start, pidf.digits, 10, QChar('0'))
                                   .arg(pidf.suffix));
        ui->patientBirthDateEdit->setDate(QDate::currentDate());
    }
    case NewStudy: {
        const CustomizedId &aidf = mainWindow->getAccNumFormat();
        int start = settings.value(ACCNUMBER_START).toInt();
        ui->accNumberEdit->setText(QString("%1%2%3").arg(aidf.prefix)
                                .arg(start, aidf.digits, 10, QChar('0'))
                                .arg(aidf.suffix));
        ui->schDateTimeEdit->setDateTime(QDateTime::currentDateTime());
    }
        break;
    case ChangeStudy:
        ui->reqPhysicianCombo->setCurrentText(patient->reqPhysician);
        ui->reqProcIDCombo->setCurrentText(patient->reqProcID);
        ui->reqProcDescCombo->setCurrentText(patient->reqProcDesc);
        if (patient->reqProcPrio == "LOW") {
            ui->reqProcPriorityCombo->setCurrentIndex(0);
        } else if (patient->reqProcPrio == "MEDIUM") {
            ui->reqProcPriorityCombo->setCurrentIndex(1);
        } else if (patient->reqProcPrio == "HIGH") {
            ui->reqProcPriorityCombo->setCurrentIndex(2);
        }
        ui->modalityCombo->setCurrentText(patient->modality);
        ui->schPhysicianCombo->setCurrentText(patient->schPhysician);
        ui->schStationAETCombo->setCurrentText(patient->schStationAET);
        ui->schStationNameCombo->setCurrentText(patient->schStationName);
        ui->schDateTimeEdit->setDateTime(patient->schDateTime);
        ui->schProcStepIDCombo->setCurrentText(patient->schProcStepID);
        ui->schProcStepDescCombo->setCurrentText(patient->schProcStepDesc);
    }

    QSqlQueryModel *model = new QSqlQueryModel(this);
    model->setQuery("SELECT PatientName FROM StudyTable ORDER BY PatientName",
                    QSqlDatabase::database(STUDY_DB_CONNECTION_NAME));
    completer = new QCompleter(this);
    completer->setModel(model);
    completer->setModelSorting(QCompleter::CaseSensitivelySortedModel);
    ui->patientNameEdit->setCompleter(completer);
}

void WorkListDialog::onOk()
{
    QSettings settings;

    if (ui->patientIDEdit->text().isEmpty() || ui->accNumberEdit->text().isEmpty() ||
            ui->patientNameEdit->text().isEmpty() || ui->patientAgeSpin->value()==0) {
        QMessageBox::critical(this, windowTitle(), tr("Entries with symbol '*' are required."));
        return;
    }

    if (mode == NewStudy || mode == NewPatient) {
        patient->fileName = QString("%1/%2/%3_%4.wl").arg(mainWindow->getDbConfig().imagePath,
                                                          mainWindow->getStationInfo().aetitle,
                                                          ui->modalityCombo->currentText(),
                                                          ui->accNumberEdit->text());
        if (QFile(patient->fileName.toLocal8Bit()).exists()) {
            QMessageBox::critical(this, windowTitle(),
                                  tr("Register failed, duplicate Accession Numbers in database."));
            return;
        }

        char uid[100];
        patient->studyUID = QString::fromLatin1(dcmGenerateUniqueIdentifier(uid, SITE_STUDY_UID_ROOT));
        patient->instanceUID = QString::fromLatin1(dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT));
        patient->creationTime = QDateTime::currentDateTime();
        patient->lastModifiedTime = patient->creationTime;

        settings.setValue(ACCNUMBER_START, settings.value(ACCNUMBER_START).toUInt()+1);
        if (mode == NewPatient)
            settings.setValue(PATIENTID_START, settings.value(PATIENTID_START).toUInt()+1);
    } else patient->lastModifiedTime = QDateTime::currentDateTime();

    patient->accNumber = ui->accNumberEdit->text();
    patient->patientID = ui->patientIDEdit->text();
    patient->patientName = ui->patientNameEdit->text();
    switch(ui->patientSexCombo->currentIndex()) {
    case 0: patient->patientSex = QString("M"); break;
    case 1: patient->patientSex = QString("F"); break;
    case 2: patient->patientSex = QString("O"); break;
    }
    patient->patientBirth = ui->patientBirthDateEdit->date();
    QString ageUnit;
    switch (ui->ageUnitCombo->currentIndex()) {
    case 0:
        ageUnit = "Y";
        break;
    case 1:
        ageUnit = "M";
        break;
    case 2:
        ageUnit = "W";
        break;
    case 3:
        ageUnit = "D";
        break;
    }
    patient->patientAge = QString::number(ui->patientAgeSpin->value()) + ageUnit;
    patient->patientSize = ui->patientSizeDSpin->value();
    patient->patientWeight = ui->patientWeightDSpin->value();
    patient->patientPhone = ui->patientPhoneCombo->currentText();
    patient->patientAddress = ui->patientAddrCombo->currentText();
    patient->admissionID = ui->admissionIdCombo->currentText();
    patient->department = ui->divisionCombo->currentText();
    patient->medicalAlerts = ui->medicalAlertsCombo->currentText();
    patient->reqPhysician = ui->reqPhysicianCombo->currentText();
    patient->reqProcID = ui->reqProcIDCombo->currentText();
    patient->reqProcDesc = ui->reqProcDescCombo->currentText();
    switch(ui->reqProcPriorityCombo->currentIndex()) {
    case 0: patient->reqProcPrio = "LOW"; break;
    case 1: patient->reqProcPrio = "MEDIUM"; break;
    case 2: patient->reqProcPrio = "HIGH"; break;
    }
    patient->schPhysician = ui->schPhysicianCombo->currentText();
    patient->schDateTime = ui->schDateTimeEdit->dateTime();
    patient->schStationAET = ui->schStationAETCombo->currentText();
    patient->schStationName = ui->schStationNameCombo->currentText();
    patient->modality = ui->modalityCombo->currentText();
    patient->schProcStepID = ui->schProcStepIDCombo->currentText();
    patient->schProcStepDesc = ui->schProcStepDescCombo->currentText();

    QString entry = ui->patientAddrCombo->currentText();
    QStringList entrylist = settings.value(PATIENT_ADDR).toStringList();
    if (!entry.isEmpty()) {
        entrylist.removeOne(entry);
        entrylist.prepend(entry);
        settings.setValue(PATIENT_ADDR, entrylist);
    }

    entry = ui->medicalAlertsCombo->currentText();
    entrylist = settings.value(MEDICAL_ALERTS).toStringList();
    if (!entry.isEmpty()) {
        entrylist.removeOne(entry);
        entrylist.prepend(entry);
        settings.setValue(MEDICAL_ALERTS, entrylist);
    }

    entry = ui->patientPhoneCombo->currentText();
    entrylist = settings.value(PATIENT_PHONES).toStringList();
    if (!entry.isEmpty()) {
        entrylist.removeOne(entry);
        entrylist.prepend(entry);
        settings.setValue(PATIENT_PHONES, entrylist);
    }

    entry = ui->admissionIdCombo->currentText();
    entrylist = settings.value(ADMISSION_IDS).toStringList();
    if (!entry.isEmpty()) {
        entrylist.removeOne(entry);
        entrylist.prepend(entry);
        settings.setValue(ADMISSION_IDS, entrylist);
    }

    entry = ui->divisionCombo->currentText();
    entrylist = settings.value(REQ_DIVISIONS).toStringList();
    if (!entry.isEmpty()) {
        entrylist.removeOne(entry);
        entrylist.prepend(entry);
        settings.setValue(REQ_DIVISIONS, entrylist);
    }

    entry = ui->reqPhysicianCombo->currentText();
    entrylist = settings.value(REQ_PHYSICIANS).toStringList();
    if (!entry.isEmpty()) {
        entrylist.removeOne(entry);
        entrylist.prepend(entry);
        settings.setValue(REQ_PHYSICIANS, entrylist);
    }

    entry = ui->reqProcIDCombo->currentText();
    entrylist = settings.value(PROCEDURE_IDS).toStringList();
    if (!entry.isEmpty()) {
        entrylist.removeOne(entry);
        entrylist.prepend(entry);
        settings.setValue(PROCEDURE_IDS, entrylist);
    }

    entry = ui->reqProcDescCombo->currentText();
    entrylist = settings.value(PROCEDURE_DESC).toStringList();
    if (!entry.isEmpty()) {
        entrylist.removeOne(entry);
        entrylist.prepend(entry);
        settings.setValue(PROCEDURE_DESC, entrylist);
    }

    entry = ui->schPhysicianCombo->currentText();
    entrylist = settings.value(PER_PHYSICIANS).toStringList();
    if (!entry.isEmpty()) {
        entrylist.removeOne(entry);
        entrylist.prepend(entry);
        settings.setValue(PER_PHYSICIANS, entrylist);
    }

    entry = ui->schStationAETCombo->currentText();
    entrylist = settings.value(STATION_AETS).toStringList();
    if (!entry.isEmpty()) {
        entrylist.removeOne(entry);
        entrylist.prepend(entry);
        settings.setValue(STATION_AETS, entrylist);
    }

    entry = ui->schStationNameCombo->currentText();
    entrylist = settings.value(STATION_NAMES).toStringList();
    if (!entry.isEmpty()) {
        entrylist.removeOne(entry);
        entrylist.prepend(entry);
        settings.setValue(STATION_NAMES, entrylist);
    }

    entry = ui->schProcStepIDCombo->currentText();
    entrylist = settings.value(PROC_STEP_ID).toStringList();
    if (!entry.isEmpty()) {
        entrylist.removeOne(entry);
        entrylist.prepend(entry);
        settings.setValue(PROC_STEP_ID, entrylist);
    }

    entry = ui->schProcStepDescCombo->currentText();
    entrylist = settings.value(PROC_STEP_DESC).toStringList();
    if (!entry.isEmpty()) {
        entrylist.removeOne(entry);
        entrylist.prepend(entry);
        settings.setValue(PROC_STEP_DESC, entrylist);
    }

    accept();
}

void WorkListDialog::onClear()
{
    ui->reqPhysicianCombo->setCurrentText(QString());
    ui->reqProcDescCombo->setCurrentText(QString());
    ui->reqProcIDCombo->setCurrentText(QString());

    ui->schPhysicianCombo->setCurrentText(QString());
    ui->schStationAETCombo->setCurrentText(QString());
    ui->schStationNameCombo->setCurrentText(QString());
    ui->schProcStepDescCombo->setCurrentText(QString());
    ui->schProcStepIDCombo->setCurrentText(QString());
}


void WorkListDialog::patientSelected(const QString &name)
{
    PatientSelectDialog dialog(name, this);
    if (QDialog::Accepted == dialog.exec()) {
        const QSqlRecord &rec = dialog.getPatient();
        ui->patientIDEdit->setText(rec.value(SqlPatientModel::PatientId).toString());
        ui->patientNameEdit->setText(rec.value(SqlPatientModel::PatientName).toString());
        ui->patientSexCombo->setCurrentText(sex2trSex(rec.value(SqlPatientModel::PatientSex).toString()));
        ui->patientBirthDateEdit->setDate(QDate::fromString(rec.value(SqlPatientModel::PatientBirth).toString(), SQLITE_DATE_FORMAT));
        ui->medicalAlertsCombo->setCurrentText(rec.value(SqlPatientModel::MedicalAlerts).toString());
        ui->patientSizeDSpin->setValue(rec.value(SqlPatientModel::PatientSize).toDouble());
        ui->patientWeightDSpin->setValue(rec.value(SqlPatientModel::PatientWeight).toDouble());
        ui->patientAddrCombo->setCurrentText(rec.value(SqlPatientModel::PatientAddr).toString());
        ui->patientPhoneCombo->setCurrentText(rec.value(SqlPatientModel::PatientPhone).toString());
        updateAge(ui->patientBirthDateEdit->date(), true);
    }
}

void WorkListDialog::updateAge(const QDate &date, bool enforce)
{
    if (enforce || ui->patientBirthDateEdit->hasFocus()) {
        QDate curDate = QDate::currentDate();
        if (curDate.year() - date.year() > 1) {
            ui->patientAgeSpin->setValue(curDate.year()-date.year());
            ui->ageUnitCombo->setCurrentIndex(0);
        } else if ((curDate.year() > date.year()) || (curDate.month() - date.month() > 1)) {
            ui->patientAgeSpin->setValue(curDate.month()-date.month()+(curDate.year()-date.year())*12);
            ui->ageUnitCombo->setCurrentIndex(1);
        } else if ((curDate.month() > date.month()) || (curDate.weekNumber()-date.weekNumber()>1)) {
            ui->patientAgeSpin->setValue(date.daysTo(curDate)/7);
            ui->ageUnitCombo->setCurrentIndex(2);
        } else {
            ui->patientAgeSpin->setValue(date.daysTo(curDate));
            ui->ageUnitCombo->setCurrentIndex(3);
        }
    }
}

void WorkListDialog::updateBirth()
{
    if (ui->ageUnitCombo->hasFocus() || ui->patientAgeSpin->hasFocus()) {
        int value = ui->patientAgeSpin->value();
        QDate curDate = QDate::currentDate();
        ui->patientBirthDateEdit->setMaximumDate(curDate);
        switch (ui->ageUnitCombo->currentIndex()) {
        case 0:
            ui->patientBirthDateEdit->setDate(curDate.addYears(-value));
            break;
        case 1:
            ui->patientBirthDateEdit->setDate(curDate.addMonths(-value));
            break;
        case 2:
            ui->patientBirthDateEdit->setDate(curDate.addDays(-(value*7)));
            break;
        case 3:
            ui->patientBirthDateEdit->setDate(curDate.addDays(-value));
            break;
        }
    }
}
